//$Id: BaseDaoImpl Dec 27, 2009 5:12:39 PM encoding UTF-8 $ QQ:199742236 $ 
package com.hd.base.dao.impl;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import cn.com.dstz.utils.FillNameQuery;
import cn.com.dstz.vo.FieldVO;

import com.hd.base.dao.BaseDao;

/**
 * Base Dao Implement
 * 
 * @author saintwe
 * 
 * @version 1.0 $ Dec 27, 2009 $ 9:54:32 PM $
 * 
 */
public class BaseDaoImpl extends HibernateDaoSupport implements BaseDao{

	public Integer batchUpdate( String HQL, Map< String, Object > valueMap )
			throws DataAccessException {
		TemplateHQL template = this.new TemplateHQL( );

		return ( Integer ) template.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {

				return query.executeUpdate( );
			}

		}, HQL, valueMap );
	}

	public void delete( final String entityName, final Object entity )
			throws DataAccessException {
		getHibernateTemplate( ).execute( new HibernateCallback( ){

			public Object doInHibernate( Session session )
					throws HibernateException, SQLException {
				session.delete( entityName, entity );
				return null;
			}

		} );
	}

	public void delete( Object entity ) throws DataAccessException {
		getHibernateTemplate( ).delete( entity );
	}

	@SuppressWarnings( "unchecked" )
	public < T > List< T > find( String HQL, Map< String, Object > valueMap,
			int firstResult, int maxResult ) throws DataAccessException {
		Template template = this.new Template( );

		return ( List< T > ) template.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {

				return( maxResult != 0 ? query.setFirstResult( firstResult )
						.setMaxResults( maxResult ).list( ) : query.list( ) );
			}

		}, HQL, valueMap, firstResult, maxResult );
	}

	@SuppressWarnings( "unchecked" )
	public < T > List< T > find( String HQL, Map< String, Object > valueMap,
			final String cacheName ) throws DataAccessException {
		Template template = this.new Template( );

		return ( List< T > ) template.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {

				return( cacheName != null ? query.setCacheable( true )
						.setCacheRegion( cacheName ).list( ) : query.list( ) );
			}

		}, HQL, valueMap, 0, 0 );
	}

	@SuppressWarnings( "unchecked" )
	public < T > List< T > findByNamedQuery( String namedQuery,
			final String cacheName, int firstResult, int maxResult,
			Object ... values ) throws DataAccessException {
		NamedExecuteFindTemplate template = this.new NamedExecuteFindTemplate( );

		return ( List< T > ) template.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {
				return( cacheName != null && maxResult > 0 ? query
						.setCacheable( true ).setCacheRegion( cacheName )
						.setFirstResult( firstResult )
						.setMaxResults( maxResult ).list( )
						: ( maxResult > 0 ? query.setFirstResult( firstResult )
								.setMaxResults( maxResult ).list( )
								: ( cacheName != null ? query.setCacheable(
										true ).setCacheRegion( cacheName )
										.list( ) : query.list( ) ) ) );
			}

		}, namedQuery, firstResult, maxResult, values );
	}

	@SuppressWarnings( "unchecked" )
	public < T > T get( String entityName, Serializable id )
			throws DataAccessException {
		return ( T ) getHibernateTemplate( ).get( entityName, id );
	}

	@SuppressWarnings( "unchecked" )
	public < T > T get( String entityName, Serializable id, LockMode lockMode )
			throws DataAccessException {
		return ( T ) getHibernateTemplate( ).get( entityName, id, lockMode );
	}

	@SuppressWarnings( "unchecked" )
	public < T > T get( String HQL, Map< String, Object > valueMap,
			final String cacheName ) throws DataAccessException {
		TemplateHQL t = this.new TemplateHQL( );

		return ( T ) t.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {
				return( cacheName != null ? query.setCacheable( true )
						.setCacheRegion( cacheName ).uniqueResult( ) : query
						.uniqueResult( ) );
			}

		}, HQL, valueMap );
	}

	@SuppressWarnings( "unchecked" )
	public < T > T getByNamedQuery( String namedQuery, final String cacheName,
			Object ... values ) throws DataAccessException {
		NamedExecuteTemplate template = this.new NamedExecuteTemplate( );

		return ( T ) template.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {

				return( cacheName != null ? query.setCacheable( true )
						.setCacheRegion( cacheName ).uniqueResult( ) : query
						.uniqueResult( ) );
			}

		}, namedQuery, 0, 0, values );
	}

	@SuppressWarnings( "unchecked" )
	public < T > T load( String entityName, Serializable id )
			throws DataAccessException {
		return ( T ) getHibernateTemplate( ).load( entityName, id );
	}

	public void load( Object entity, Serializable id )
			throws DataAccessException {
		getHibernateTemplate( ).load( entity, id );
	}

	@SuppressWarnings( "unchecked" )
	public < T > T load( String entityName, Serializable id, LockMode lockMode )
			throws DataAccessException {
		return ( T ) getHibernateTemplate( ).load( entityName, id, lockMode );
	}

	public void persist( String entityName, Object entity ) {
		getHibernateTemplate( ).persist( entityName, entity );
	}

	public void save( String entityName, Object entity )
			throws DataAccessException {
		getHibernateTemplate( ).save( entityName, entity );
	}

	public void saveOrUpdate( String entityName, Object entity )
			throws DataAccessException {
		getHibernateTemplate( ).saveOrUpdate( entityName, entity );
	}

	public void update( String entityName, Object entity ) {
		getHibernateTemplate( ).update( entityName, entity );
	}

	public Integer update( String HQL, Map< String, Object > valueMap )
			throws DataAccessException {
		TemplateHQL t = this.new TemplateHQL( );

		return ( Integer ) t.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {
				return Integer.valueOf( query.executeUpdate( ) );
			}

		}, HQL, valueMap );
	}

	public Integer updateByNamedQuery( String namedQuery, Object ... values )
			throws DataAccessException {
		NamedExecuteTemplate template = this.new NamedExecuteTemplate( );

		return ( Integer ) template.rowMapper( new RowMapper( ){

			public Object execute( Query query, int firstResult, int maxResult ) {
				return query.executeUpdate( );
			}

		}, namedQuery, 0, 0, values );
	}

	private static interface RowMapper{
		Object execute( Query query, int firstResult, int maxResult );
	}

	/**
	 * 处理 HQL
	 * 
	 * @author saintwe
	 * 
	 * @version 1.0 $ Dec 27, 2009 $ 9:51:38 PM $
	 * 
	 */
	private class Template{
		Object rowMapper( final RowMapper rowMapper, final String HQL,
				final Map< String, Object > valueMap, final int firstResult,
				final int maxResult ) {
			return getHibernateTemplate( ).executeFind(
					new HibernateCallback( ){

						public Object doInHibernate( Session session )
								throws HibernateException, SQLException {
							Query query = session.createQuery( HQL );
							String [ ] namedParams = query.getNamedParameters( );

							for ( int i = 0; i < namedParams.length; i++ ){
								Object value = valueMap.get( namedParams[ i ] );

								if( value instanceof Collection ){
									query.setParameterList( namedParams[ i ],
											( Collection ) value );
									
								}else if( value instanceof Object [ ] ){
									query.setParameterList( namedParams[ i ],
											( Object [ ] ) value );
									
								}else{
									query
											.setParameter( namedParams[ i ],
													value );
								}

								value = null;
							}
							return rowMapper.execute( query, firstResult,
									maxResult );
						}

					} );

		}
	}

	/**
	 * 处理 HQL
	 * 
	 * @author saintwe
	 * 
	 * @version 1.0 $ Dec 27, 2009 $ 9:50:59 PM $
	 * 
	 */
	private class TemplateHQL{
		Object rowMapper( final RowMapper rowMapper, final String HQL,
				final Map< String, Object > valueMap ) {
			
			return getHibernateTemplate( ).execute( new HibernateCallback( ){

				public Object doInHibernate( Session session )
						throws HibernateException, SQLException {
					Query query = session.createQuery( HQL );
					String namedParams[] = query.getNamedParameters( );

					for ( int i = 0; i < namedParams.length; i++ ){
						Object value = valueMap.get( namedParams[ i ] );

						if( value instanceof Collection ){
							query.setParameterList( namedParams[ i ],
									( Collection ) value );
							
						}else if( value instanceof Object [ ] ){
							query.setParameterList( namedParams[ i ],
									( Object [ ] ) value );
							
						}else{
							query.setParameter( namedParams[ i ], value );
						}
						value = null;
					}
					return rowMapper.execute( query, 0, 0 );
				}

			} );
		}
	}

	/**
	 * 处理命名参数
	 * 
	 * 该方法执行UPDATE OR DELETE OR BATCHDELETE, BATCHUPDATE 等HQL 操作. 使用命名查询
	 * 
	 * @author saintwe
	 * 
	 * @version 1.0 $ Dec 27, 2009 $ 8:58:45 PM $
	 * 
	 */
	private class NamedExecuteTemplate{
		Object rowMapper( final RowMapper namedInterface,
				final String namedQuery, int firstResult, int maxResult,
				final Object ... values ) {
			return getHibernateTemplate( ).execute( new HibernateCallback( ){

				public Object doInHibernate( Session session )
						throws HibernateException, SQLException {
					Query query = session.getNamedQuery( namedQuery );
					Map< String, Object > valueMap = FillNameQuery.fillValue( query
							.getQueryString( ), values );
					String [ ] namedParameters = query.getNamedParameters( );

					for ( int i = 0; i < namedParameters.length; i++ ){
						String param = namedParameters[ i ];
						Object value = valueMap.get( param );
						if( value instanceof Collection ){
							query
									.setParameterList( param,
											( Collection ) value );
						}else if( value instanceof Object [ ] ){
							query
									.setParameterList( param,
											( Object [ ] ) value );
						}else{
							query.setParameter( param, value );
						}
						value = null;
						param = null;
					}
					return namedInterface.execute( query, 0, 0 );
				}

			} );

		}
	}

	/**
	 * Execute the specified action assuming that the result object is a list
	 * 
	 * This is a convenience method for executing Hibernate find calls or
	 * queries within an action.
	 * 
	 * @author saintwe
	 * 
	 * @version 1.0 $ Dec 27, 2009 $ 9:26:24 PM $
	 * 
	 */
	private class NamedExecuteFindTemplate{
		Object rowMapper( final RowMapper namedInterface,
				final String namedQuery, final int firstResult,
				final int maxResult, final Object ... values ) {
			return getHibernateTemplate( ).executeFind(
					new HibernateCallback( ){

						public Object doInHibernate( Session session )
								throws HibernateException, SQLException {
							Query query = session.getNamedQuery( namedQuery );
							Map< String, Object > valueMap = FillNameQuery.fillValue(
									query.getQueryString( ), values );
							String [ ] namedParameters = query
									.getNamedParameters( );

							for ( int i = 0; i < namedParameters.length; i++ ){
								String param = namedParameters[ i ];
								Object value = valueMap.get( param );

								if( value instanceof Collection ){
									query.setParameterList( param,
											( Collection ) value );

								}else if( value instanceof Object [ ] ){
									query.setParameterList( param,
											( Object [ ] ) value );
								}else{
									query.setParameter( param, value );
								}

								value = null;
								param = null;
							}
							return namedInterface.execute( query, firstResult,
									maxResult );
						}

					} );

		}
	}

	// 通过sql语句查询记录条数；
	public int getListCountBySql( String sql ) {
		return ( ( Integer ) ( getHibernateTemplate( ).getSessionFactory( )
				.getCurrentSession( ).createSQLQuery( sql ).addScalar( "a",
						Hibernate.INTEGER ).uniqueResult( ) ) ).intValue( );
	}

	// 通过sql语句查询记录；
	public List getListBySql( String sql, int currentPage, int pageNums ) {

		// return findListBySQLQuery( sql, currentPage * pageNums, pageNums );

		return getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( )
				.createSQLQuery( sql ).setFirstResult( currentPage * pageNums )
				.setMaxResults( pageNums ).list( );
	}

	// ==============================================================

	public int batchSaveOrUpdate( List< String > sqls )  throws Exception{

		Session session = getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( );
		
		Connection conn = session.connection( );
		Statement stmt = null;

		try{
			stmt = conn.createStatement( );
			for ( String sql : sqls ){
				stmt.addBatch( sql );
			}

			int [ ] batchs = stmt.executeBatch( );

			if( batchs == null ){
				return 0;
			}

		}finally{
			if( stmt != null ){
				stmt.close( );
				stmt = null;
			}
		}

		return 1;

	}

	public int saveAndReturnLastInsert( String sql ) throws Exception {
		Session session = getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( );
		Connection conn = session.connection( );
		PreparedStatement pstmt = null;
		int id = 0;
		ResultSet rs = null;

		try{
			pstmt = conn.prepareStatement( sql );

			pstmt.setEscapeProcessing( false );

			int rows = pstmt.executeUpdate( );

			if( rows > 0 ){
				rs = pstmt.executeQuery( "SELECT last_insert_id()" );
				if( rs.next( ) ){
					id = rs.getInt( 1 );
				}
			}

		}finally{
			if( rs != null ){
				rs.close( );
				rs = null;
			}
			if( pstmt != null ){
				pstmt.close( );
				pstmt = null;
			}
		}

		return id;
	}

	public Map< String, Object > getData( String sql ) throws Exception {

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		Map< String, Object > row = null;

		try{
			Session session = getHibernateTemplate( ).getSessionFactory( )	.getCurrentSession( );
			conn = session.connection( );

			pstmt = conn.prepareStatement( sql );
			rs = pstmt.executeQuery( );
			ResultSetMetaData rsmd = rs.getMetaData( );
			int columnCount = rsmd.getColumnCount( );
			List< FieldVO > fields = new ArrayList< FieldVO >( columnCount );
			FieldVO field = null;
			for ( int i = 1; i <= columnCount; i++ ){
				field = new FieldVO( );
				field.setName( rsmd.getColumnLabel( i ) );
				field.setInt( rsmd.getColumnTypeName( i ).contains( "INT" ) );
				fields.add( field );
			}
			rsmd = null;
			row = new HashMap< String, Object >( columnCount );
			if( rs.next( ) ){

				for ( FieldVO obj : fields ){
					if( obj.isInt( ) ){
						row.put( obj.getName( ), rs.getInt( obj.getName( ) ) );
					}else{
						row
								.put( obj.getName( ), rs.getString( obj
										.getName( ) ) );
					}
				}
			}

		}finally{
			if( rs != null ){
				rs.close( );
				rs = null;
			}
			if( pstmt != null ){
				pstmt.close( );
				pstmt = null;
			}
		}
		return row;

	}

	/**
	 * 执行添加删除更新操作
	 */
	public int saveOrUpdate( String sql ) throws Exception {
		
		Session session = getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( );
		PreparedStatement pstmt = null;
		
		try{
			Connection conn = session.connection( );
			pstmt = conn.prepareStatement( sql );
			pstmt.setEscapeProcessing( false );
		
			return pstmt.executeUpdate( );
		}finally{
			if( pstmt != null ){
				pstmt.close( );
			}
		}
	}

	/**
	 * 统计数据
	 */
	public int count( String sql, Map< String, Object > valueMap )  throws Exception{
		Session session = getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( );
		SQLQuery query = session.createSQLQuery( sql );
		setParam( valueMap, query );
		return ( Integer ) query.addScalar( "a", Hibernate.INTEGER ).uniqueResult( );
	}

	/**
	 * 返回单个数据
	 */
	public Map< String, Object > get( String sql, Map< String, Object > valueMap )  throws Exception{
		Session session = getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( );
		SQLQuery query = session.createSQLQuery( sql );
		query.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP ); // 将结果设置为map
																		// 返回
		setParam( valueMap, query );

		return ( Map< String, Object > ) query.uniqueResult( );
	}
	
	public List< Map< String, Object >> findListBySQLQuery( String sql, int beginSize, int pageSize, Map< String, Object> valueMap, Map< String, Type > aliasMap ) throws Exception{
		
		Session session = getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( );
		SQLQuery query = session.createSQLQuery( sql );
		
		query.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP ); // 将结果设置为map
		setParam( valueMap, query );
		
		setAlias( aliasMap, query );
		
		List< Map< String, Object > > queryList = query.setFirstResult( beginSize ).setMaxResults( pageSize ).list( );
		
		return queryList;
	}
	
	/**
	 * 以SQL形式查询数据
	 * @param sql
	 * @param beginSize
	 * @param pageSize
	 * @return
	 */
	public List< Map< String, Object >> findListBySQLQuery( String sql, int beginSize, int pageSize, Map< String, Object > valueMap ) throws Exception {
		return findListBySQLQuery( sql, beginSize, pageSize, valueMap, null );
	}

	public List< Map< String, Object >> findAllListBySQLQuery( String sql, Map< String, Object > valueMap ) {
		Session session = getHibernateTemplate( ).getSessionFactory( ).getCurrentSession( );
		SQLQuery query = session.createSQLQuery( sql );
		query.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP ); // 将结果设置为map
																		// 返回
		setParam( valueMap, query );
		List< Map< String, Object > > queryList = query.list( );

		return queryList;
	}
	
	private void setAlias( Map< String, Type > aliasMap, SQLQuery query ){
		
		if( aliasMap == null || aliasMap.isEmpty( ) ){
			return;
		}
		
		for ( Entry < String, Type > entry : aliasMap.entrySet ( ) ) {
			query.addScalar( entry.getKey( ), entry.getValue( ) );
		}
		
	}

	private void setParam( Map< String, Object > valueMap, SQLQuery query ) {

		if( valueMap != null && !valueMap.isEmpty( ) ){
			String [ ] nameParameters = query.getNamedParameters( );

			for ( String param : nameParameters ){

				Object value = valueMap.get( param );
				if( value instanceof Collection ){
					query.setParameterList( param, ( Collection ) value );

				}else if( value instanceof Object [ ] ){
					query.setParameterList( param, ( Object [ ] ) value );
				}else{
					query.setParameter( param, value );
				}

				param = null;
				value = null;
			}
		}
	}
	
	
}
